# Copyright (C) 2007 Laszlo Pandy <laszlok2@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

import decimal
Dec = decimal.Decimal


SHARE_NONE, SHARE_EQUAL, SHARE_EXACT, SHARE_PERCENT = ALL_SHARE_TYPES = range(4)

class ShareProfile:
	def __init__(self):
		self.shareDict = {}
		
	def __cmp__(self, object):
		if hasattr(object, "shareDict"):
			return cmp(self.shareDict, object.shareDict)
		return -1
	
	def __len__(self):
		return len(self.shareDict)
	
	def __iter__(self):
		return iter(self.shareDict)
	
	def __contains__(self, object):
		return (object in self.shareDict)
	
	def copy(self):
		s = ShareProfile()
		s.shareDict = self.shareDict.copy()
		return s
		
	def setPersonShare(self, person, shareType, value=None):
		if shareType == SHARE_NONE:
			if person in self.shareDict:
				del self.shareDict[person]
		elif shareType == SHARE_EQUAL:
			self.shareDict[person] = (SHARE_EQUAL, None)
		elif shareType == SHARE_PERCENT:
			self.shareDict[person] = (shareType, int(value))
		elif shareType == SHARE_EXACT:
			self.shareDict[person] = (shareType, Dec(value))
		
	def getPersonShare(self, person):
		if person in self.shareDict:
			return self.shareDict[person]
		else:
			return (SHARE_NONE, None)
	
	def calculateShares(self, total):
		total = Dec(total)
		old_total = total
		equalList = []
		sharesDict = {}
		
		for person, (shareType, value) in self.shareDict.iteritems():
			if shareType == SHARE_EQUAL:
				equalList.append(person)
			elif shareType == SHARE_EXACT:
				sharesDict[person] = Dec(value)
			elif shareType == SHARE_PERCENT:
				sharesDict[person] = (total * value) / 100
				
		for value in sharesDict.itervalues():
			total = total - value
		
		# check the old total and total to deal with cases where the bill's total is negative
		if old_total < 0 and total > 0:
			raise OverTotalException()
		elif old_total > 0 and total < 0:
			raise OverTotalException()
		elif equalList:
			rest = total / len(equalList)
			for person in equalList:
				sharesDict[person] = rest
		elif total > 0:
			#if there were no people in the equalList, and there is still total left, we have a problem
			raise UnderTotalException()
		
		return sharesDict
			
	def calculatePersonShare(self, person, total):
		shareDict = self.calculateShares(total)
		if person in shareDict:
			return shareDict[person]
		else:
			return Dec(0)
		
	def swapPerson(self, person, newPerson):
		if person in self.shareDict:
			val = self.shareDict[person]
			del self.shareDict[person]
			if newPerson:
				self.shareDict[newPerson] = val
				
	def getPrettyString(self):
		strings = []
		for person, (shareType, value) in self.shareDict.iteritems():
			if shareType == SHARE_EQUAL:
				strings.append(str(person))
			elif shareType == SHARE_EXACT:
				strings.append("%s (%.2f)" % (str(person), value))
			elif shareType == SHARE_PERCENT:
				strings.append("%s (%d%%)" % (str(person), value))
		
		strings.sort()
		return ", ".join(strings)

class OverTotalException(Exception):
	pass

class UnderTotalException(Exception):
	pass
